﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace Cli
{
    class Program
    {
        static void Main (string [] args)
        {
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("A conectarse se ha dicho!");

            //for (int j= 0; j < 3; j ++)
            for (int j = 0; j < 1; j++)
            //for (; ; )
            {
                int start = Environment.TickCount;
                using (TcpClient cliente = new TcpClient())
                {
                    // desactivo el algoritmo de nagle
                    cliente.NoDelay = true;

                    try
                    {
                        cliente.Connect("localhost", 2666);
                    }
                    catch (IOException)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("El servidor parece no estar listo");
                        continue;
                    }
                    catch (Exception exx)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine(exx.Message);
                        continue;
                    }

                    using (NetworkStream ns = cliente.GetStream())
                    {
                        Console.WriteLine(
                            "Tarde {0} milis en conectar",
                            Environment.TickCount - start
                        );

                        try
                        {
                            Console.ForegroundColor = ConsoleColor.DarkGray;

                            for (int i = 0; i < 50; i++)
                            //for (int i = 0; ; i++)
                            {
                                parseResponse(ns);

                                //ns.Write(Cmd.mkStringCmd("culo"));
                                //ns.Write(Cmd.mkStringCmd("concha"));
                                ns.Write("!");

                                //if (i % 1000 == 0)
                                //    Console.WriteLine(i);
                            }

                            Console.WriteLine("Intentando mandar un fin");
                            
                            parseResponse(ns);

                            ns.Write(Cmd.mkStringCmd("fin")); // <- mando un comando "fin"
                            Console.WriteLine("Mande fin al servidor");
                        }
                        catch (IOException)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine("Nos patearon");
                            int foo = 0;
                        }
                        catch (Exception exx)
                        {
                            Console.ForegroundColor = ConsoleColor.Red;
                            Console.WriteLine(exx.Message);
                            int foo = 0;
                        }
                    }
                }
            }
        }

        static void parseResponse(NetworkStream ns)
        {
            for (; ; )
            {
                int @byte = ns.ReadByte();

                if (@byte == '!')
                {
                    break;
                }
                else if (@byte == '*')
                {
                    if (! executeCmd (ns, Cmd.parseCmd(ns)))
                        break;
                }
                else
                {
                    throw new Exception(
                        string.Format("unknown byte '{0}' in response", @byte)
                    );
                }
            }
        }

        static bool executeCmd(NetworkStream ns, List<byte[]> cmd)
        {
            string cmdFirst = Encoding.ASCII.GetString(cmd[0]);

            switch (cmdFirst)
            {
                case "tick":
                    // si hay comandos del cliente es hora de
                    // escribirlos en el networkstream...
                    break;
                case "func":
                    if (cmd.Count > 1)
                    {
                        Console.WriteLine(Encoding.ASCII.GetString(cmd[1]));
                    }
                    break;
                default:
                    throw new Exception(
                        string.Format("unknown '{0}' command", cmdFirst)
                    );
            }

            return true;
        }
    }
}
